/*
 ============================================================================
 Name		: WebData.cpp
 Author	  : Vitaly Yevtushenko
 Version	 : 1.0
 Copyright   : Licensed under GPL V2
 Description : CWebData implementation
 ============================================================================
 */
#include <e32debug.h>
#include <f32file.h>
#include <s32file.h>
#include <e32cmn.h>

#include "WebData.h"

const TInt KPointArrayGranularity(4);
const TInt KLineArrayGranularity(4);

#define DEL(obj) if (obj) { delete obj; obj = NULL; }

CWebData::CWebData() :
	iTappedId(-1)
	{
	// No implementation required
	}

CWebData::~CWebData()
	{
	DEL(iVertexes);
	DEL(iLines);
	}

CWebData* CWebData::NewLC()
	{
	CWebData* self = new (ELeave) CWebData();
	CleanupStack::PushL(self);
	self->ConstructL();
	return self;
	}

CWebData* CWebData::NewL()
	{
	CWebData* self = CWebData::NewLC();
	CleanupStack::Pop(); // self;
	return self;
	}

void CWebData::ConstructL()
	{
	iVertexes = new (ELeave) CArrayFixFlat<TPoint> (KPointArrayGranularity);
	iLines = new (ELeave) CArrayFixFlat<TLine> (KLineArrayGranularity);

	TestWebDataL();
	}

void CWebData::TestWebDataL()
	{
	/*
	//points
	iVertexes->AppendL(TPoint(40, 540));	//0
	iVertexes->AppendL(TPoint(320, 320));	//1
	iVertexes->AppendL(TPoint(40, 320));	//2
	iVertexes->AppendL(TPoint(320, 540));	//3
	iVertexes->AppendL(TPoint(320, 100));	//4
	iVertexes->AppendL(TPoint(40, 100));	//5

	//lines
	iLines->AppendL(TLine(0, 1));
	iLines->AppendL(TLine(1, 5));
	iLines->AppendL(TLine(5, 3));
	iLines->AppendL(TLine(3, 2));
	iLines->AppendL(TLine(2, 4));
	iLines->AppendL(TLine(4, 0));
	*/
	TInt num_vertexes(10);
	for (TInt i=0; i<num_vertexes; ++i)
		{
		iVertexes->AppendL(TPoint(180, 320));
		if (i>0)
			iLines->AppendL(TLine(i-1, i));
		}
	iLines->AppendL(TLine(0,num_vertexes-1));
	}

TInt CWebData::Line(const TInt aLineNum, TPoint &aP1, TPoint &aP2,
		TBool &aCrossed)
	{
	if (iLines && iVertexes && aLineNum >= 0 && aLineNum < iLines->Count())
		{
		aP1 = iVertexes->At(iLines->At(aLineNum).iP1);
		aP2 = iVertexes->At(iLines->At(aLineNum).iP2);

		aCrossed = EFalse;

		//vertex id's
		TInt id1(iLines->At(aLineNum).iP1), id2(iLines->At(aLineNum).iP2);

		//search for crosses
		for (TInt i = 0; i < iLines->Count(); ++i)
			{
			//line can't be crossed with self
			if (i == aLineNum)
				continue;

			//crossed lines can't have common vertexes
			if (id1 == iLines->At(i).iP1 || id1 == iLines->At(i).iP2 || 
					id2	== iLines->At(i).iP1 || id2 == iLines->At(i).iP2)
				continue;

			if (IsLinesCrossed(aP1, aP2, iVertexes->At(iLines->At(i).iP1),
					iVertexes->At(iLines->At(i).iP2)))
				{
				aCrossed = ETrue;
				break;
				}
			}

		if (aCrossed)
			iSolved = EFalse;
			
		return KErrNone;
		}
	else
		return KErrNotFound;
	}

TInt CWebData::Point(const TInt aPointNum, TPoint &aPoint, TBool &aTapped)
	{
	if (aPointNum >= 0 && aPointNum < iVertexes->Count())
		{
		aPoint = iVertexes->At(aPointNum);
		aTapped = aPointNum == iTappedId;
		return KErrNone;
		}
	else
		return KErrNotFound;
	}

TInt CWebData::PointTapped(const TPoint &aTapPoint)
	{
	if (iVertexes)
		{
		for (TInt i = 0; i < iVertexes->Count(); i++)
			{
			TPoint p(iVertexes->At(i));
			if (aTapPoint.iX >= p.iX - KVertexRadius * 2 && aTapPoint.iX
					<= p.iX + KVertexRadius * 2 && aTapPoint.iY >= p.iY
					- KVertexRadius * 2 && aTapPoint.iY <= p.iY + KVertexRadius
					* 2)
				{
				iTappedId = i;
				return iTappedId;
				}
			}
		}
	return KErrNotFound;
	}

TInt CWebData::DragTo(const TPoint &aPosition)
	{
	if (iVertexes && iTappedId >= 0 && iTappedId < iVertexes->Count())
		{
		iVertexes->At(iTappedId) = aPosition;
		iSolved = ETrue;
		return KErrNone;
		}

	return KErrNotFound;
	}

TBool CWebData::IsLinesCrossed(const TPoint &aP11, const TPoint &aP12,
		const TPoint &aP21, const TPoint &aP22)
	{
	if (aP11 == aP21 || aP11 == aP22 || aP12 == aP21 || aP12 == aP22)
		return ETrue;
	
	TPoint dir1 = aP12 - aP11;
	TPoint dir2 = aP22 - aP21;

	TReal a1 = -dir1.iY;
	TReal b1 = +dir1.iX;
	TReal d1 = -(a1 * aP11.iX + b1 * aP11.iY);

	TReal a2 = -dir2.iY;
	TReal b2 = +dir2.iX;
	TReal d2 = -(a2 * aP21.iX + b2 * aP21.iY);

	TReal seg1_line2_start = a2 * aP11.iX + b2 * aP11.iY + d2;
	TReal seg1_line2_end = a2 * aP12.iX + b2 * aP12.iY + d2;

	TReal seg2_line1_start = a1 * aP21.iX + b1 * aP21.iY + d1;
	TReal seg2_line1_end = a1 * aP22.iX + b1 * aP22.iY + d1;

	if (seg1_line2_start * seg1_line2_end >= 0 || seg2_line1_start * seg2_line1_end >= 0)
		return EFalse;

	return ETrue;
	}

void CWebData::SaveL(const TFileName &aFileName)
	{
	//connect to filesystem
	RFs fs;
	User::LeaveIfError(fs.Connect());
	CleanupClosePushL(fs);
	
	//delete just for my nurves
	fs.Delete(aFileName);
	
	//create file
	RFile file;
	User::LeaveIfError(file.Create(fs, aFileName, EFileWrite));
	CleanupClosePushL(file);
	
	//write vertex count
	TPckg<TInt> vertexcount(iVertexes->Count());
	file.Write(vertexcount);
	
	//write vertexes
	for (TInt i=0; i<iVertexes->Count(); ++i)
		{
		TPckg<TPoint> point(iVertexes->At(i));
		file.Write(point);
		}
	
	//write lines count
	TPckg<TInt> linescount(iLines->Count());
	file.Write(linescount);
	
	//write lines
	for (TInt i=0; i<iLines->Count(); ++i)
		{
		TPoint p(iLines->At(i).iP1, iLines->At(i).iP2);
		TPckg<TPoint> point(p);
		file.Write(point);
		}
	
	CleanupStack::PopAndDestroy(2, &fs); //fws, file, fs
	}

void CWebData::LoadL(const TFileName &aFileName)
	{
	//connect to filesystem
	RFs fs;
	User::LeaveIfError(fs.Connect());
	CleanupClosePushL(fs);
	
	//open file
	RFile file;
	User::LeaveIfError(file.Open(fs, aFileName, EFileRead));
	CleanupClosePushL(file);
	
	iVertexes->Reset();
	iLines->Reset();
	
	//read vertex count
	TInt vertexes;
	TPckg<TInt> vertexcount(vertexes);
	file.Read(vertexcount);	
	
	//read vertexes	
	for (TInt i=0; i<vertexes; ++i)
		{
		TPoint p;
		TPckg<TPoint> point(p);
		file.Read(point);
		iVertexes->AppendL(p);
		}
	
	//read lines count
	TInt linec;
	TPckg<TInt> linescount(linec);
	file.Read(linescount);
	
	//write lines
	for (TInt i=0; i<linec; ++i)
		{
		TPoint p;
		TPckg<TPoint> point(p);
		file.Read(point);
		iLines->AppendL(TLine(p.iX, p.iY));
		}
	
	CleanupStack::PopAndDestroy(2, &fs); //fws, file, fs
	}

